<template>
  <div class="ma-editor-container">
    <div
      ref="editorContainer"
      class="monaco-editor-container"
      :style="{ height: `${height}px` }"
    ></div>
    <!--    <div v-show="!scripts.length" class="ma-empty-container">-->
    <!--      <div class="ma-hot-key">-->
    <!--        <p>-->
    <!--          保存<em>Ctrl + S</em><br />-->
    <!--          测试<em>Ctrl + Q</em><br />-->
    <!--          代码提示<em>Alt + /</em><br />-->
    <!--          恢复断点<em>F8</em><br />-->
    <!--          步进<em>F6</em>-->
    <!--        </p>-->
    <!--      </div>-->
    <!--    </div>-->

    <magic-dialog
      :moveable="false"
      :title="'历史记录：' + (info && info.name)"
      :value="showHistoryDialog"
      align="right"
      height="750px"
      maxWidth="inherit"
      padding="none"
      width="80%"
      @on-close="showHistoryDialog = false"
    >
      <template #content>
        <magic-history ref="history" />
      </template>
      <template #buttons>
        <button
          class="ma-button active"
          @click="
            () => {
              if (history) history.reset()
              showHistoryDialog = false
            }
          "
        >
          恢复
        </button>
        <button class="ma-button" @click="showHistoryDialog = false">关闭</button>
      </template>
    </magic-dialog>
    <magic-dialog :value="showImageDialog" title="图片结果" @on-close="showImageDialog = false">
      <template #content>
        <p align="center"><img :src="imageUrl" /></p>
      </template>
      <template #buttons>
        <button class="ma-button" @click="showImageDialog = false">确定</button>
      </template>
    </magic-dialog>
  </div>
</template>

<script lang="ts" setup>
import { ref, onMounted, nextTick, onBeforeUnmount, getCurrentInstance, computed } from 'vue'

import * as monaco from 'monaco-editor'
import { initializeMagicScript } from './scripts/editor/magic-script.js'
import bus from './scripts/bus.js'
import MagicDialog from '@/components/MagicEditor/src/views/components/modal/magic-dialog.vue'
import MagicHistory from './magic-history.vue'
import request from '@/components/MagicEditor/src/api/request.js'
// import request from '@/config/axios'
import contants from './scripts/contants.js'
import * as utils from './scripts/utils.js'
import store from './scripts/store.js'
import { Parser } from './scripts/parsing/parser.js'
import tokenizer from './scripts/parsing/tokenizer.js'
import { TokenStream } from './scripts/parsing/index.js'
import RequestParameter from './scripts/editor/request-parameter.js'

import JavaClass from './scripts/editor/java-class.js'
// import './styles/index.css' // 引入全局样式文件

// 声明全局属性扩展
declare module '@vue/runtime-core' {
  interface ComponentCustomProperties {
    $magicAlert: (message: string, type?: string) => void
  }
}

// 定义脚本项接口
interface ScriptItem {
  id?: string
  tmp_id?: string
  name?: string
  content?: string
  modified?: boolean
  ext?: {
    decorations?: any[]
    [key: string]: any
  }
  [key: string]: any
}

// 请求配置接口定义
interface RequestConfig {
  baseURL: string
  url: string
  method: string
  headers: Record<string, any>
  responseType: string
  withCredentials: boolean
  params?: Record<string, any>
  data?: any
  transformRequest?: any[]
}

// 获取应用实例以访问全局API
const instance = getCurrentInstance()
const proxy = instance?.proxy

// 响应式状态
const scripts = ref<ScriptItem[]>([])
const selected = ref<ScriptItem | null>(null)
const info = ref<ScriptItem | null>(null)
const editor = ref<monaco.editor.IStandaloneCodeEditor | null>(null)
const showImageDialog = ref(false)
const imageUrl = ref('')
const showHistoryDialog = ref(false)

// DOM引用
const scrollbar = ref<HTMLElement | null>(null)
const editorContainer = ref<HTMLElement | null>(null)
const history = ref<any | null>(null)

// 其他变量
let timeout: NodeJS.Timeout | null = null
let resizeObserver: ResizeObserver | null = null
let layoutTimeout: NodeJS.Timeout | null = null
let resizeDebounceTimeout: number | null = null

// 存储编辑器注册的事件处理器，用于后续清理
const editorEventDisposables: monaco.IDisposable[] = []

// 为编辑器添加事件监听器，并自动管理其生命周期
const addEditorEventListener = (eventHandler: monaco.IDisposable) => {
  if (eventHandler) {
    editorEventDisposables.push(eventHandler)
  }
}

// 添加一个工具函数进行装饰器批量操作
const batchUpdateDecorations = (decorationsArray: any[], newDecorations: any[]) => {
  if (!editor.value || !editor.value.getModel()) return decorationsArray

  // 如果已有装饰器，先清除
  if (decorationsArray && decorationsArray.length > 0) {
    editor.value.getModel()!.deltaDecorations(decorationsArray, [])
  }

  // 添加新装饰器
  if (newDecorations && newDecorations.length > 0) {
    return editor.value.getModel()!.deltaDecorations([], newDecorations)
  }

  return []
}

// 验证编辑器内容
const doValidate = () => {
  if (!editor.value) return

  try {
    let parser = new Parser(new TokenStream(tokenizer(editor.value.getValue())))
    parser.parse()
    if (editor.value.getModel()) {
      monaco.editor.setModelMarkers(editor.value.getModel()!, 'validate', [])
    }
  } catch (e: any) {
    if (e.span && editor.value.getModel()) {
      let line = e.span.getLine()
      monaco.editor.setModelMarkers(editor.value.getModel()!, 'validate', [
        {
          startLineNumber: line.lineNumber,
          endLineNumber: line.endLineNumber,
          startColumn: line.startCol,
          endColumn: line.endCol,
          message: e.message,
          severity: monaco.MarkerSeverity.Error
        }
      ])
    }
  }
}

// 更新编辑器布局（优化版本）
const layout = () => {
  // 防止频繁调用layout
  if (layoutTimeout) {
    clearTimeout(layoutTimeout)
  }

  layoutTimeout = setTimeout(() => {
    if (editorContainer.value && utils.isVisible(editorContainer.value) && editor.value) {
      editor.value.layout()
    }
    layoutTimeout = null
  }, 100)
}

// 保存API
const doSaveApi = () => {
  if (!info.value) return

  if (!info.value.headers) {
    info.value.headers = []
  }

  let thisInfo = info.value
  let saveObj: Partial<ScriptItem> = { ...thisInfo }
  delete saveObj.optionMap
  delete saveObj.ext

  if (saveObj.parameters) {
    saveObj.parameters = saveObj.parameters.filter((it) => it.name)
  }
  if (saveObj.paths) {
    saveObj.paths = saveObj.paths.filter((it) => it.name)
  }
  if (saveObj.headers) {
    saveObj.headers = saveObj.headers.filter((it) => it.name)
  }

  // 修复类型错误，使用as any绕过类型检查
  const optionString = JSON.stringify(saveObj.option)
  ;(saveObj as any).option = optionString

  return request
    .send('/save', JSON.stringify(saveObj), {
      method: 'post',
      headers: {
        'Content-Type': 'application/json'
      },
      transformRequest: []
    })
    .success((id) => {
      if (saveObj.id) {
        bus.emit('script_save')
      } else {
        bus.emit('script_add')
      }
      if (thisInfo) {
        thisInfo.id = id
      }
    })
}

// 保存函数
const doSaveFunction = () => {
  if (!info.value) return

  let thisInfo = info.value
  let saveObj: Partial<ScriptItem> = { ...thisInfo }
  delete saveObj.ext

  if (saveObj.parameters) {
    saveObj.parameters = saveObj.parameters.filter((it) => it.name)
  }

  return request
    .send('/function/save', JSON.stringify(saveObj), {
      method: 'post',
      headers: {
        'Content-Type': 'application/json'
      },
      transformRequest: []
    })
    .success((id) => {
      if (saveObj.id) {
        bus.emit('function_save')
      } else {
        bus.emit('function_add')
      }
      if (thisInfo) {
        thisInfo.id = id
      }
    })
}

// 保存脚本
const doSave = () => {
  if (selected.value) {
    if (info.value && info.value._type === 'api') {
      return doSaveApi()
    } else {
      return doSaveFunction()
    }
  }
}

// 测试脚本
const doTest = () => {
  if (!selected.value) {
    if (proxy) {
      proxy.$magicAlert({
        content: '请打开接口在执行测试'
      })
    }
  } else {
    bus.emit('switch-tab', 'request')
    if (info.value && (info.value.running || info.value._type !== 'api')) {
      return
    }
    if (contants.AUTO_SAVE) {
      // 自动保存
      let resp = doSave()
      resp && resp.end(() => internalTest())
    } else {
      internalTest()
    }
  }
}

// 优化内部测试逻辑
const internalTest = () => {
  if (!editor.value || !info.value) return

  // 使用单次操作来清除错误标记
  const model = editor.value.getModel()
  if (model) {
    const errorDecorations = model
      .getAllDecorations()
      .filter((it) => it.options.inlineClassName === 'squiggly-error')
      .map((it) => it.id)

    if (errorDecorations.length > 0) {
      model.deltaDecorations(errorDecorations, [])
    }
  }

  bus.emit('status', '开始测试...')
  if (info.value.ext) {
    info.value.ext.running = true
  }
  info.value.running = true

  let requestConfig: RequestConfig = Object.freeze({
    baseURL: contants.SERVER_URL,
    url: utils.replaceURL('/' + info.value.groupPath + '/' + info.value.path),
    method: info.value.method || 'GET',
    headers: {},
    responseType: 'json',
    withCredentials: true
  })

  if (info.value.paths) {
    info.value.paths
      .filter((it) => it.value && it.value.trim())
      .forEach((it) => {
        requestConfig.url = requestConfig.url.replace(
          new RegExp(`\\{${it.name}\\}`, 'g'),
          it.value.trim()
        )
      })
  }

  // 先处理接口的路径变量，再处理分组的路径变量，顺序递归向上
  if (proxy && proxy.$parent && proxy.$parent.$refs.apiList) {
    const groups = proxy.$parent.$refs.apiList.getGroupsById(info.value.groupId)
    groups
      .filter((group) => group.paths && group.paths.length > 0)
      .forEach((group) => {
        group.paths
          .filter((it) => it.value && it.value.trim())
          .forEach((it) => {
            requestConfig.url = requestConfig.url.replace(
              new RegExp(`\\{${it.name}\\}`, 'g'),
              it.value.trim()
            )
          })
      })
  }

  if (requestConfig.url.indexOf('{') > -1) {
    if (proxy) {
      proxy.$magicAlert({
        content: '请填写路径变量后在测试！'
      })
    }
    info.value.running = false
    if (info.value.ext) {
      info.value.ext.running = false
    }
    return
  }

  if (info.value.headers) {
    info.value.headers
      .filter((it) => it.name)
      .forEach((it) => {
        requestConfig.headers[it.name] = it.value
      })
  }

  let params: Record<string, any> = {}
  if (info.value.parameters) {
    info.value.parameters
      .filter((it) => it.name)
      .forEach((it) => {
        params[it.name] = it.value
      })
  }

  requestConfig.headers['Content-Type'] = 'application/x-www-form-urlencoded'

  if (requestConfig.method !== 'POST' || info.value.requestBody) {
    requestConfig.params = params
  } else {
    requestConfig.data = params
  }

  if (info.value.requestBody) {
    try {
      JSON.parse(info.value.requestBody)
      requestConfig.params = params
      requestConfig.data = info.value.requestBody
      requestConfig.headers['Content-Type'] = 'application/json'
      requestConfig.transformRequest = []
    } catch (e) {
      if (proxy) {
        proxy.$magicAlert({
          content: 'RequestBody 参数有误，请检查！'
        })
      }
      info.value.running = false
      if (info.value.ext) {
        info.value.ext.running = false
      }
      return
    }
  }

  const currentInfo = info.value
  if (currentInfo.ext) {
    currentInfo.ext.eventSource = request.createConsole()
    currentInfo.ext.eventSource.addEventListener('create', (e: any) => {
      bus.emit('report', 'run')
      nextTick(() => sendTestRequest(currentInfo, requestConfig, currentInfo.ext.sessionId))
    })

    currentInfo.ext.eventSource.addEventListener('log', (e: any) => {
      let row = JSON.parse(e.data)
      row.timestamp = utils.formatDate(new Date())
      let throwable = row.throwable
      delete row.throwable
      if (currentInfo.ext) {
        currentInfo.ext.logs.push(row)

        if (throwable) {
          let messages = throwable.replace(/ /g, '&nbsp;').split('\n')
          for (let i = 0; i < messages.length; i++) {
            currentInfo.ext.logs.push({
              level: row.level,
              message: messages[i],
              throwable: true
            })
          }
        }
      }
    })

    currentInfo.ext.eventSource.addEventListener('close', (e: any) => {
      if (currentInfo.ext && currentInfo.ext.eventSource) {
        currentInfo.ext.eventSource.close()
      }
    })
  }
}

// 查看历史
const viewHistory = () => {
  if (!selected.value) {
    return
  }

  if (!info.value.id) {
    proxy.$magicAlert({
      content: '当前是新增脚本,无法查看历史记录'
    })
    return
  }

  let url = `backups?id=${info.value.id}`
  let isApi = info.value._type === 'api'

  if (!isApi) {
    url = 'function/' + url
  }

  request.send(url).success((timestampes) => {
    if (timestampes && timestampes.length > 0) {
      history.value.load(timestampes, info.value, editor.value, isApi)
      showHistoryDialog.value = true
    } else {
      proxy.$magicAlert({
        title: '历史记录',
        content: '当前脚本无历史记录'
      })
    }
  })
}

// 继续执行
const doContinue = (step?: boolean) => {
  if (!selected.value || !info.value) {
    return
  }

  let target = info.value
  if (target.ext && target.ext.debuging) {
    target.ext.debuging = false
    target.ext.variables = []

    let requestConfig: Partial<RequestConfig> = {
      ...(target.ext.requestConfig || {})
    }

    delete requestConfig.data
    delete requestConfig.params
    if (requestConfig.headers) {
      requestConfig.headers[contants.HEADER_REQUEST_CONTINUE] = true
      requestConfig.headers[contants.HEADER_REQUEST_STEP_INTO] = step === true
    }

    sendTestRequest(target, requestConfig as RequestConfig, target.ext.sessionId)
  }
}

// 步进
const doStepInto = () => {
  doContinue(true)
}

// 合并全局设置
const mergeGlobalSettings = (requestConfig: RequestConfig) => {
  let parameters = JSON.parse(store.get('global-parameters') || '[]')
  let headers = JSON.parse(store.get('global-headers') || '[]')

  headers
    .filter((it) => it.name)
    .forEach((item) => {
      requestConfig.headers[item.name] = requestConfig.headers[item.name] || item.value
    })

  parameters
    .filter((it) => it.name)
    .forEach((item) => {
      if (requestConfig.params) {
        requestConfig.params[item.name] = requestConfig.params[item.name] || item.value
      } else if (requestConfig.data) {
        // 检查requestConfig.data是否为对象
        if (typeof requestConfig.data === 'object' && requestConfig.data !== null) {
          requestConfig.data[item.name] = requestConfig.data[item.name] || item.value
        }
      }
    })
}

// 发送测试请求
const sendTestRequest = (target: ScriptItem, requestConfig: RequestConfig, sessionId: string) => {
  bus.emit('switch-tab', 'log')
  if (target.ext) {
    target.ext.requestConfig = requestConfig
    target.ext.sessionId = sessionId
  }
  requestConfig.headers[contants.HEADER_REQUEST_SESSION] = sessionId
  requestConfig.headers[contants.HEADER_MAGIC_TOKEN] = contants.HEADER_MAGIC_TOKEN_VALUE

  mergeGlobalSettings(requestConfig)

  if (editor.value && editor.value.getModel()) {
    requestConfig.headers[contants.HEADER_REQUEST_BREAKPOINTS] = editor.value
      .getModel()!
      .getAllDecorations()
      .filter((it) => it.options.linesDecorationsClassName === 'breakpoints')
      .map((it) => it.range.startLineNumber)
      .join(',')
  } else {
    requestConfig.headers[contants.HEADER_REQUEST_BREAKPOINTS] = ''
  }

  request
    .execute(requestConfig)
    .then((res) => {
      if (target.ext) {
        if (target.ext.debugDecorations && editor.value) {
          editor.value.deltaDecorations(target.ext.debugDecorations, [])
        }
        target.ext.debugDecorations = target.ext.debugDecoration = null
      }

      if (res.headers[contants.HEADER_RESPONSE_WITH_MAGIC_API] === 'true') {
        let data = res.data

        if (data.code === contants.RESPONSE_CODE_SCRIPT_ERROR) {
          bus.emit('report', 'script_error')
          bus.emit('status', '脚本执行出错..')
          // 脚本执行出错
          if (target.ext) {
            target.ext.debuging = false
          }
          target.running = false

          if (data.body) {
            let line = data.body
            if (info.value && info.value.id === target.id && editor.value) {
              let range = new monaco.Range(line[0], line[2], line[1], line[3] + 1)
              let decorations = editor.value.deltaDecorations(
                [],
                [
                  {
                    range,
                    options: {
                      hoverMessage: {
                        value: data.message
                      },
                      inlineClassName: 'squiggly-error'
                    }
                  }
                ]
              )

              editor.value.revealRangeInCenter(range)
              editor.value.focus()

              if (contants.DECORATION_TIMEOUT >= 0) {
                setTimeout(() => {
                  if (editor.value) {
                    editor.value.deltaDecorations(decorations, [])
                  }
                }, contants.DECORATION_TIMEOUT)
              }
            }
          }

          target.responseBody = utils.formatJson(data.data)
          bus.emit('switch-tab', 'result')
          bus.emit('update-response-body', target.responseBody)
          if (target.ext && target.ext.eventSource) {
            target.ext.eventSource.close()
          }
        } else if (data.code == contants.RESPONSE_CODE_DEBUG) {
          bus.emit('report', 'debug_in')
          bus.emit('status', '进入断点...')
          // 进入断点
          if (target.ext) {
            target.ext.debuging = true
            target.ext.variables = data.body.variables
          }

          let range = data.body.range
          let decoration = {
            range: new monaco.Range(range[0], 1, range[0], 1),
            options: {
              isWholeLine: true,
              inlineClassName: 'debug-line',
              className: 'debug-line'
            }
          }

          if (target.ext) {
            target.ext.debugDecoration = decoration
            if (editor.value && editor.value.getModel()) {
              target.ext.debugDecorations = [editor.value.deltaDecorations([], [decoration])]
            }
          }

          bus.emit('switch-tab', 'debug')
        } else {
          bus.emit('status', '脚本执行完毕')
          // 执行完毕
          target.running = false
          bus.emit('switch-tab', 'result')

          let contentType = res.headers[contants.HEADER_RESPONSE_MAGIC_CONTENT_TYPE]

          if (contentType === contants.HEADER_APPLICATION_STREAM) {
            // 下载
            var disposition = res.headers[contants.HEADER_CONTENT_DISPOSITION]
            var filename = 'output'

            if (disposition) {
              filename = decodeURIComponent(
                disposition.substring(disposition.indexOf('filename=') + 9)
              )
            }

            target.responseBody = utils.formatJson({ filename })
            bus.emit('update-response-body', target.responseBody)

            let a = document.createElement('a')
            a.download = filename
            let bstr = atob(data.data)
            let n = bstr.length
            let u8arr = new Uint8Array(n)

            while (n--) {
              u8arr[n] = bstr.charCodeAt(n)
            }

            a.href = window.URL.createObjectURL(new Blob([u8arr]))
            a.click()
            bus.emit('report', 'output_blob')
          } else if (contentType && contentType.indexOf('image') === 0) {
            // 图片
            imageUrl.value = `data:${contentType};base64,${data.data}`
            showImageDialog.value = true
            target.responseBody = utils.formatJson(data.data)
            bus.emit('update-response-body', target.responseBody)
            bus.emit('report', 'output_image')
          } else if (data.code == contants.RESPONSE_NO_PERMISSION) {
            if (proxy) {
              proxy.$magicAlert({
                title: '无权限',
                content: '您没有权限执行测试'
              })
            }
          } else {
            target.responseBody = utils.formatJson(data.data)
            bus.emit('update-response-body', target.responseBody)
          }

          if (target.ext && target.ext.eventSource) {
            target.ext.eventSource.close()
          }
        }
      } else {
        if (target.ext) {
          target.ext.debuging = false
        }
        target.running = false
        bus.emit('switch-tab', 'result')
        bus.emit('status', '脚本执行完毕')

        try {
          if (target.ext && target.ext.eventSource) {
            target.ext.eventSource.close()
          }
          target.responseBody = utils.formatJson(res.data)
          bus.emit('update-response-body', target.responseBody)
        } catch (ignored) {}
      }
    })
    .catch((error) => {
      if (target.ext) {
        target.ext.debuging = false
      }
      target.running = false
      if (target.ext && target.ext.eventSource) {
        target.ext.eventSource.close()
      }
      request.processError(error)
    })
}

// 关闭脚本
const close = (id) => {
  scripts.value.forEach((item, index) => {
    if (item.id === id || item.tmp_id === id) {
      scripts.value.splice(index, 1)

      if (selected.value === item) {
        let nextInfo

        if (index > 0) {
          nextInfo = scripts.value[index - 1]
        } else if (scripts.value.length > 0) {
          nextInfo = scripts.value[0]
        } else {
          selected.value = null
          return
        }

        open(nextInfo)
      }
    }
  })

  if (scripts.value.length === 0) {
    bus.emit('opened', { empty: true })
  }
}

// 更新脚本内容
const changed = (changedInfo) => {
  if (changedInfo && changedInfo === selected.value) {
    let index = -1

    scripts.value.forEach((item, i) => {
      if (item.id === changedInfo.id) {
        index = i
      }
    })

    if (index > -1) {
      scripts.value[index] = changedInfo
    }
  }
}

// 接受父组件参数
interface Props {
  modelValue: string
  language: string
  theme: string
  height: number
}

const props = withDefaults(defineProps<Props>(), {
  modelValue: '',
  language: 'magicscript',
  theme: 'vs',
  height: 300
})

// 添加自定义$magicAlert和$parent类型声明
declare global {
  interface ComponentCustomProperties {
    $magicAlert: (options: any) => void
    $magicContextmenu: (options: any) => void
    $parent: any
  }
}

self.MonacoEnvironment = {
  getWorker: function (_workerId: string, label: string) {
    const workerMap: Record<string, URL> = {
      json: new URL('monaco-editor/esm/vs/language/json/json.worker.js', import.meta.url),
      css: new URL('monaco-editor/esm/vs/language/css/css.worker.js', import.meta.url),
      html: new URL('monaco-editor/esm/vs/language/html/html.worker.js', import.meta.url),
      typescript: new URL('monaco-editor/esm/vs/language/typescript/ts.worker.js', import.meta.url),
      javascript: new URL('monaco-editor/esm/vs/language/typescript/ts.worker.js', import.meta.url),
      default: new URL('monaco-editor/esm/vs/editor/editor.worker.js', import.meta.url)
    }

    return new Worker(workerMap[label] || workerMap.default, { type: 'module' })
  }
}

onBeforeMount(() => {
  Promise.all([JavaClass.initClasses(), JavaClass.initImportClass()])
    .then((e) => {
      // this.hideLoading()
      // this.login()
      // if (this.config.checkUpdate !== false) {
      //   this.checkUpdate()
      // }
    })
    .catch((e) => {
      // this.hideLoading()
      // this.$magicAlert({
      //   title: '加载失败',
      //   content: '请检查配置项baseURL是否正确！'
      // })
    })
})

// 懒加载编辑器处理
let editorInitialized = false
let delayedInitTimeout: number | null = null

const lazyInitEditor = () => {
  if (editorInitialized || !editorContainer.value) return

  // 标记已初始化
  editorInitialized = true

  // 使用最小配置创建编辑器 - 禁用不必要的功能提高性能
  editor.value = monaco.editor.create(editorContainer.value, {
    value: props.modelValue,
    language: props.language,
    theme: props.theme,
    automaticLayout: true,
    minimap: { enabled: false },
    scrollBeyondLastLine: false,
    lineNumbers: 'on',
    scrollbar: {
      vertical: 'auto',
      horizontal: 'auto'
    },
    renderWhitespace: 'none',
    // 禁用性能密集型功能
    hover: { enabled: false },
    occurrencesHighlight: false,
    selectionHighlight: false,
    renderLineHighlight: 'none',
    links: false,
    contextmenu: false,
    folding: false,
    renderControlCharacters: false,
    wordWrap: 'off',
    quickSuggestions: false,
    parameterHints: { enabled: false },
    suggest: {
      showIcons: false,
      maxVisibleSuggestions: 3,
      snippetsPreventQuickSuggestions: false
    }
  })

  // 添加必要的事件处理
  if (editor.value) {
    // 简化的内容变化监听，使用高延迟防抖
    addEditorEventListener(
      editor.value.onDidChangeModelContent(
        debounce(() => {
          if (info.value && editor.value && editor.value.getModel()) {
            try {
              info.value.content = editor.value.getModel()!.getValue()

              if (!info.value.modified) {
                info.value.modified = true
              }
            } catch (e) {
              // 忽略可能的错误
            }
          }
        }, 1000) // 使用更高的延迟来减少处理频率
      )
    )
  }
}

// 组件挂载 - 极简版本
onMounted(() => {
  // 设置容器高度
  if (editorContainer.value) {
    editorContainer.value.style.height = `${props.height}px`
  }

  // 延迟加载编辑器 - 仅初始化基本事件总线
  bus.on('update-window-size', layout)
  bus.on('open', open)
  bus.on('changed', changed)
  bus.on('doSave', doSave)
  bus.on('viewHistory', viewHistory)
  bus.on('doTest', doTest)
  bus.on('doContinue', doContinue)
  bus.on('doStepInto', doStepInto)
  bus.on('ready-delete', () => {
    if (info.value) {
      bus.emit('delete-api', info.value)
    }
  })

  // 延迟1秒后初始化编辑器，避免页面渲染阻塞
  delayedInitTimeout = window.setTimeout(() => {
    try {
      // 初始化Monaco环境
      initializeMagicScript()

      // 初始化编辑器
      lazyInitEditor()

      // 如果需要打开初始脚本
      if (scripts.value && scripts.value.length > 0) {
        setTimeout(() => {
          try {
            open(scripts.value[0])
          } catch (e) {
            console.error('打开初始脚本失败', e)
          }
        }, 500)
      }
    } catch (e) {
      console.error('编辑器初始化失败', e)
    }
  }, 1000)
})

// 清理和销毁组件
onBeforeUnmount(() => {
  // 清理延迟初始化定时器
  if (delayedInitTimeout !== null) {
    window.clearTimeout(delayedInitTimeout)
    delayedInitTimeout = null
  }

  // 清理其他潜在计时器
  if (timeout !== null) {
    clearTimeout(timeout)
    timeout = null
  }

  if (layoutTimeout !== null) {
    clearTimeout(layoutTimeout)
    layoutTimeout = null
  }

  if (resizeDebounceTimeout !== null) {
    clearTimeout(resizeDebounceTimeout)
    resizeDebounceTimeout = null
  }

  // 清理事件监听器
  editorEventDisposables.forEach((disposable) => {
    try {
      disposable.dispose()
    } catch (e) {
      // 忽略错误
    }
  })
  editorEventDisposables.length = 0

  // 断开ResizeObserver
  if (resizeObserver) {
    try {
      resizeObserver.disconnect()
    } catch (e) {
      // 忽略错误
    }
    resizeObserver = null
  }

  // 清理编辑器
  if (editor.value) {
    try {
      // 先设置为空内容，减少清理负担
      editor.value.setValue('')
      // 移除可能的所有模型
      const model = editor.value.getModel()
      if (model) {
        monaco.editor.setModelMarkers(model, 'validate', [])
      }
      // 销毁编辑器
      editor.value.dispose()
    } catch (e) {
      // 忽略错误
    }
    editor.value = null
  }

  // 清理事件总线监听
  bus.off('update-window-size', layout)
  bus.off('open', open)
  bus.off('changed', changed)
  bus.off('doSave', doSave)
  bus.off('viewHistory', viewHistory)
  bus.off('doTest', doTest)
  bus.off('doContinue', doContinue)
  bus.off('doStepInto', doStepInto)
  bus.off('ready-delete')

  // 清理数据引用
  scripts.value = []
  info.value = null
  selected.value = null
})

// 缓存断点装饰器选项，避免重复创建对象
const BREAKPOINT_DECORATION_OPTIONS = {
  isWholeLine: true,
  linesDecorationsClassName: 'breakpoints',
  className: 'breakpoint-line'
}

// 创建断点装饰函数
const createBreakpointDecoration = (line: number) => {
  return {
    range: new monaco.Range(line, 1, line, 1),
    options: BREAKPOINT_DECORATION_OPTIONS
  }
}

// 事件处理函数memoization
const memoizedHandlers = {
  tabClick: new Map<string, (e: MouseEvent) => void>(),
  contextMenu: new Map<string, (e: MouseEvent) => void>(),
  closeClick: new Map<string, (e: MouseEvent) => void>()
}

// 获取或创建Tab点击处理函数
const getOrCreateTabClickHandler = (item: ScriptItem) => {
  const key = item.id || item.tmp_id || ''
  if (!memoizedHandlers.tabClick.has(key)) {
    const handler = () => open(item)
    memoizedHandlers.tabClick.set(key, handler)
  }
  return memoizedHandlers.tabClick.get(key)!
}

// 获取或创建Tab右键菜单处理函数
const getOrCreateContextMenuHandler = (item: ScriptItem, index: number) => {
  const key = item.id || item.tmp_id || ''
  if (!memoizedHandlers.contextMenu.has(key)) {
    const handler = (e: MouseEvent) => tabsContextmenuHandle(e, item, index)
    memoizedHandlers.contextMenu.set(key, handler)
  }
  return memoizedHandlers.contextMenu.get(key)!
}

// 获取或创建关闭按钮处理函数
const getOrCreateCloseHandler = (item: ScriptItem) => {
  const key = item.id || item.tmp_id || ''
  if (!memoizedHandlers.closeClick.has(key)) {
    const handler = (e: MouseEvent) => {
      e.stopPropagation()
      close(item.id || item.tmp_id || '')
    }
    memoizedHandlers.closeClick.set(key, handler)
  }
  return memoizedHandlers.closeClick.get(key)!
}

// 清理memoized处理函数
const cleanupMemoizedHandlers = () => {
  memoizedHandlers.tabClick.clear()
  memoizedHandlers.contextMenu.clear()
  memoizedHandlers.closeClick.clear()
}

// 优化鼠标事件处理
const setupMouseEventHandlers = () => {
  if (!editor.value) return

  addEditorEventListener(
    editor.value.onMouseDown((e) => {
      // 快速返回无效点击
      if (!e.target || !e.target.element || e.target.element.classList.contains('codicon')) {
        return
      }

      // 检查是否点击在左侧空白区域 (断点区域)
      const leftMarginClick =
        e.target.type === monaco.editor.MouseTargetType.GUTTER_LINE_NUMBERS ||
        (e.target.position && e.target.position.column <= 2)

      if (leftMarginClick) {
        const line = e.target.position?.lineNumber
        if (!line || !editor.value || !editor.value.getModel()) return

        // 跳过空行
        if (editor.value.getModel()!.getLineContent(line).trim() === '') {
          return
        }

        // 获取当前行的装饰
        let decorations = editor.value.getLineDecorations(line) || []
        let breakpointDecorations = decorations.filter(
          (it) => it.options.linesDecorationsClassName === 'breakpoints'
        )

        // 切换断点状态
        if (breakpointDecorations && breakpointDecorations.length > 0) {
          // 移除断点
          editor.value.getModel()!.deltaDecorations([breakpointDecorations[0].id], [])
        } else {
          // 添加断点 - 使用缓存函数创建装饰
          editor.value.getModel()!.deltaDecorations([], [createBreakpointDecoration(line)])
        }

        // 更新当前脚本的装饰
        if (info.value && info.value.ext && editor.value.getModel()) {
          info.value.ext.decorations = editor.value.getModel()!.getAllDecorations()
        }
      }
    })
  )
}

// 计算可见的脚本Tab，使用虚拟渲染提高性能
const MAX_VISIBLE_TABS = 15 // 最大可见标签数量
const visibleScripts = computed(() => {
  if (scripts.value.length <= MAX_VISIBLE_TABS) {
    return scripts.value
  }

  // 找到当前选中标签的索引
  const selectedIndex = scripts.value.findIndex((s) => s === selected.value)

  if (selectedIndex === -1) {
    // 如果没有选中标签，则显示前MAX_VISIBLE_TABS个
    return scripts.value.slice(0, MAX_VISIBLE_TABS)
  }

  // 确保选中标签在可见区域的中间位置
  const half = Math.floor(MAX_VISIBLE_TABS / 2)
  let start = Math.max(0, selectedIndex - half)
  let end = Math.min(scripts.value.length, start + MAX_VISIBLE_TABS)

  // 如果end到达数组末尾，需要调整start
  if (end === scripts.value.length) {
    start = Math.max(0, end - MAX_VISIBLE_TABS)
  }

  return scripts.value.slice(start, end)
})

// 自定义debounce函数
function debounce<T extends (...args: any[]) => any>(
  func: T,
  delay: number = 300
): (...args: Parameters<T>) => void {
  let timeout: number | null = null

  return function (...args: Parameters<T>): void {
    if (timeout !== null) {
      clearTimeout(timeout)
    }

    timeout = window.setTimeout(() => {
      func(...args)
      timeout = null
    }, delay)
  }
}

// 实现监听内容变化函数
const setupContentChangeListener = () => {
  if (!editor.value) return

  // 使用自定义debounce函数
  const debouncedValidate = debounce(() => {
    if (info.value && info.value.ext && editor.value) {
      internalTest(info.value)
    }
  }, 300)

  // 添加内容变更监听
  addEditorEventListener(
    editor.value.onDidChangeModelContent(() => {
      // 更新当前脚本内容
      if (info.value && editor.value && editor.value.getModel()) {
        info.value.content = editor.value.getModel()!.getValue()

        // 设置修改状态
        if (!info.value.modified) {
          info.value.modified = true
        }
      }

      // 延迟验证以减少性能开销
      debouncedValidate()
    })
  )
}
</script>

<style lang="scss" scoped>
.monaco-editor-container {
  width: 100%;
  border: 1px solid #dcdfe6;
  border-radius: 4px;
  overflow: hidden; /* 确保编辑器不溢出 */
}

/* .monaco-editor-container {
  width: 100%;
  height: 100%;
  min-height: 200px;
} */
.ma-editor-container {
  position: relative;
  display: flex;
  flex-direction: column;
  flex: 1;
  height: 100%;
  margin-left: -5px;
  overflow: hidden;
}

.ma-wrapper {
  width: 100%;
  height: 30px;
  line-height: 30px;
  overflow: hidden;
  flex: none !important;
  border-bottom: 1px solid var(--tab-bar-border-color);
}

.ma-wrapper .ma-tab .ma-icon:first-child {
  padding-right: 3px;
  font-size: 16px;
}

.ma-wrapper .ma-tab .ma-svg-icon {
  height: 16px;
  margin-left: 0;
}

.ma-hot-key {
  position: absolute;
  top: 50%;
  width: 100%;
  margin-top: -60px;
  font-size: 16px;
  color: var(--empty-color);
  text-align: center;
}

.ma-hot-key p {
  display: inline-block;
  line-height: 30px;
  text-align: left;
}

.ma-hot-key p em {
  margin-left: 15px;
  font-style: normal;
  color: var(--empty-key-color);
}

.ma-empty-container {
  position: absolute;
  z-index: 2;
  width: 100%;
  height: 100%;
  flex: none !important;
  background: var(--empty-background);
}

ul {
  display: flex;
  align-items: center;
  width: 100%;
  overflow: hidden;
  flex-wrap: nowrap;
  white-space: nowrap;
  list-style-type: none;
  background: var(--background);
}

ul li {
  display: flex;
  justify-content: center;
  align-items: center;
  height: 30px;
  padding: 0 10px;
  line-height: 33px;
  color: var(--color);
  background: var(--background);
  border-bottom: 3px solid transparent;
}

ul li.selected {
  color: var(--selected-color);
  border-bottom: 3px solid #4083c9;
}

ul li:hover {
  background: var(--hover-background);
}

ul li i {
  margin-left: 5px;
  color: var(--icon-color);
  font-size: 0.5em;
}

.ma-editor-container > div {
  flex: 1;
}
</style>
